<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>

    // 实例化对象都有原型属性([[Prototype]]) => 指向构造函数(创建该实例化对象构造函数)的原型对象(prototype)

    // 构造函数 => 创建实例化对象
    function Cat(name, color) {
        // {}
        // {}[[Prototype]] = Cat.prototype   {}.__proto__ = Cat.prototype  => 所有的实例化对象都有原型属性([[Prototype]]) => 指向构造函数的原型对象(prototype)   !!!!!!!!
        // this -> {}   强制将this指向创建的实例化对象

        this.name = name;
        this.color = color;

        // return this;
    }

    // protptype(原型对象 => 对象) => 存储所有实例化对象共有的属性和方法  => 供所有的实例化对象访问
    Cat.prototype.species = "Cat";
    Cat.prototype.call = function () {
        console.log("喵喵");
    }
    Cat.prototype.skill = function () {
        console.log("捉老鼠");
    }
    Cat.prototype.say = function () {
        // this指向 => 调用此方法的实例化对象
        console.log(this.name, this.color);
    }

    Object.prototype.a = 1;
    Object.prototype.b = 2;


    // 实例化对象属性和方法的查找机制
    // 1. 自己有就找自己的   
    // 2. 自己没有就顺着原型属性([[Prototype]]) => 找构造函数(创建该实例化对象的构造函数)的原型对象(Cat.prototype)
    // 3. 如果构造函数的原型对象(Cat.prototype)也找不到 => 到哪里找?  (到构造函数Object.prototype上查找)
    // 4. 如果构造函数Object的原型对象(Object.prototype)也找不到 => 不在向后查找

    // Tom -> Tom[[Prototype]](Cat.prototype) => Cat.prototype[[Prototype]](Object.prototype) ->

    var Tom = new Cat("Tom", "black");
    console.log(Tom);

    // 1. 自己有就找自己的   
    // console.log(Tom.name, Tom.color);

    // 2. 自己没有就顺着原型属性([[Prototype]]) => 找构造函数(创建该实例化对象的构造函数)的原型对象(Cat.prototype)
    // console.log(Tom.species);
    // console.log(Tom.call);
    // console.log(Tom.skill);
    // console.log(Tom.say);

    // Tom.say();

    // 3. 如果构造函数Cat的原型对象(Cat.prototype)也找不到 => 到哪里找?  (到构造函数Object.prototype上查找)
    // 解析: 原型对象(Cat.prototype)本身是一个对象数据(实例化对象) => 原型对象是由哪个构造函数创建? Object
    // console.log(Cat.prototype);
    // 证明: 获取Cat.prototype[[Prototype]] 判断它指向谁?
    // 老版本
    // console.log(Cat.prototype.__proto__ === Object.prototype);  // true
    // 新版本
    // console.log(Object.getPrototypeOf(Cat.prototype) === Object.prototype); // true


    // console.log(Tom.a);
    // console.log(Tom.b);


    // 4. 如果构造函数Object的原型对象(Object.prototype)也找不到 => 到哪里找?
    // 解析: 原型对象(Object.prototype)本身是一个对象数据(实例化对象) => 原型对象是由哪个构造函数创建?  (Object)
    // console.log(Object.prototype);  // {}

    // 如果是由Object创建的(Object.prototype) 就会引发两个问题
    // 1. 构造函数Obejct => 自己创建了自己的原型对象
    // 2. 如果结论成立  Tom -> Cat.prototype -> Object.prototype -> Object.prototype -> Object.prototype ... 查找会无限查找 不会结束  => 影响浏览器的性能

    // 官方强制规定
    // Object.prototype[[Prototype]] = null;  //后面不在向后查找

    // 证明:  获取Object.prototype[[Prototype]] 判断它指向谁
    // 老版本
    // console.log(Object.prototype.__proto__ === null);  // true
    // 新版本
    // console.log(Object.getPrototypeOf(Object.prototype) === null); // true

    // 结论:
    //  Tom -> Tom[[Prototype]](Cat.prototype) => Cat.prototype[[Prototype]](Object.prototype) -> null


    // 原型链: 实例化对象上属性和方法的链式查找机制

    // console.log(Tom.hello);





</script>

</html>